home *** CD-ROM | disk | FTP | other *** search
/ Programming Sound Cards / Programming Sound Cards.iso / sound_57 / samplasm.asm < prev    next >
Assembly Source File  |  1995-01-01  |  23KB  |  769 lines

  1. ;
  2. ;   SAMPLASM.ASM
  3. ;   ------------
  4. ;
  5. ; One voice sampler playback system using fractional addition       16/3/89
  6. ;
  7. ;   with optional patch to drive PC speaker using PWM
  8. ;
  9. ;   For use with SAMPLER.PAS  V2
  10. ;
  11. ;
  12. ;
  13. ;
  14. ;                   (C) Copyright 1989 by Rowan McKenzie
  15. ;
  16. ;                  You may copy these files  or use the source  code  only
  17. ;        for non-profit purposes. Please contact me if you wish to use any
  18. ;        part of the package for commercial purposes.
  19. ;
  20. ;
  21. ;                       Rowan McKenzie 
  22. ;                       35 Moore Ave,
  23. ;                       Croydon 3136
  24. ;                       Vic Australia
  25. ;
  26. ;
  27. ;
  28. ;   This code provides the assembler section of SAMPLER.PAS
  29. ;
  30. ;     This version uses the system timer for sample timing, and is therefore
  31. ;   clock speed independent, although the CPU must be able to keep up with
  32. ;   the interrupt rate (20kHz!).
  33. ;
  34. ;
  35. ;
  36. ; Notes:
  37. ; ------
  38. ;
  39. ;  To assemble the D to A converter version, set pwm equ false
  40. ;
  41. ;  To assemble the PWM version, set pwm equ true
  42. ;
  43. ;  The D/A version uses the system timer (at 20kHz) to synchronise output
  44. ;     samples (and to make the code clock speed independent)
  45. ;
  46. ;  The PWM version uses the system timer in the same way, but triggers the
  47. ;     speaker timer channel as a monostable whose pulse length is proportional
  48. ;     to the sample value. Note that time constants are all scaled assuming
  49. ;     20kHz sample rate. If another sample rate is used, these will need to be
  50. ;     recalculated. Also, faster sampling rates mean lower effective resolution
  51. ;     from the one shot because it is clocked at a fixed frequency. The current
  52. ;     setup gives the equivalent of a 6 bit d/a converter (I know that's not
  53. ;     very good, but it's better than most PC speakers can justify!)
  54. ;
  55. ;
  56. ;
  57. ;  Variables defined in Pascal source:
  58. ;  -----------------------------------
  59. ;
  60. ;  release is a boolean variable indicating whether key releases should
  61. ;          terminate sound playback
  62. ;
  63. ;  loop is a boolean variable indicating that the loop section of the sample
  64. ;          should be played continuously after playback is complete
  65. ;
  66. ;  daout is an integer variable containing the d/a converter port
  67. ;          (for D/A version)
  68. ;
  69. ;  increment is an integer variable containing a fractional increment constant which
  70. ;          determines the pitch of the note to be played
  71. ;
  72. ;  bufloop is an integer variable containing the offset of the start of the
  73. ;          loop section
  74. ;
  75. ;  bufend is an integer variable containing the offset of the end of the sample
  76. ;          (for when the sample code is implemented)
  77. ;
  78. ;  bufstart is an integer variable containing the offset of the start of the
  79. ;          sample
  80. ;
  81. ;  kbdmode is a boolean variable indicating whether keyboard service routine
  82. ;          should pass control to bios (false) or handle the key itself (true)
  83. ;
  84. ;  kbdflag is a byte variable to indicate a key has been pressed during replay
  85. ;
  86. ;  keyval is a byte variable which will contain the scan code of a key pressed
  87. ;          during replay
  88. ;
  89. ;  tconstant is a byte variable which sets the system timer rate (20kHz)
  90. ;
  91. ;  timer is a boolean variable which indicates the timer should be used
  92. ;          to determine how long notes should last
  93. ;
  94. ;  tinterval is an integer variable indicating how long a note should be
  95. ;          played for (no. interrupts mod modulus)
  96. ;
  97. ;  modulus is a byte variable which determines after how many interrupts the
  98. ;          tinterval counter should be decremented
  99. ;
  100. ;  song is a boolean variable indicating whether a song is being played
  101. ;
  102. ;  trigger is an integer variable describing the minimum input level required
  103. ;          to begin sampling
  104. ;
  105.  
  106.         page    255,132
  107. title sampler asm module
  108.  
  109. ; ===== Equates =====
  110.  
  111. true    equ     1
  112. false   equ     0
  113.  
  114. pwm     equ     false                   ;pwm version if true else d/a version
  115.  
  116. tdelay  equ     2                       ;delay constant between samples while
  117.                                         ; waiting for trigger
  118. lshiftr equ     170                     ;scan code for left shift release
  119. rshiftr equ     182
  120. tccont  equ     43h                     ;control reg of 8253 timer chip
  121. tccount equ     42h                     ;counter reg 2 (speaker)
  122.  
  123. speaker equ     97                      ;speaker port for PWM version
  124.  
  125. data     segment word public
  126. ;
  127. ; data
  128. ;
  129.  
  130.         extrn   tconstant:word,keyval:word,kbdflag:word,bufstart:word
  131.         extrn   bufend:word,bufloop:word,increment:word,daout:word,loop:word
  132.         extrn   release:word,timer:word,tinterval:word,modulus:word,song:word
  133.         extrn   trigger:word,kbdmode:word,quickexit:word,buffer:word
  134.         extrn   bufferw:word,bufflen:word
  135.  
  136. sysold  dd      ?                       ;temp storage for old system int vector
  137. sptemp  dw      ?                       ;storage for sp for quick exit
  138. duration dw     ?                       ;duration counter
  139. modul   db      ?                       ;local modulus counter
  140.  
  141. data    ends
  142.  
  143. code    segment byte public
  144.         assume  cs:code,ds:data
  145.  
  146.         public  restore,sample,initial,replay,replayt,scalewave,echo
  147.  
  148. kbdold  dd      ?                       ;temp storage for old kbd int vector
  149. dstemp  dw      ?                       ;holds ds incase it's needed
  150.  
  151.  
  152. ;************************************************************
  153. ;
  154. ;  Restore  - restore int vectors and exits
  155. ;
  156. ;************************************************************
  157.  
  158. restore proc near
  159.         cli                                     ;restore old kbd interrupt
  160.         push    ds
  161.         mov     dx,word ptr cs:[kbdold]
  162.         mov     ds,word ptr cs:[kbdold+2]
  163.         mov     ax,2509h
  164.         int     21h                             ;restore old kbd vector
  165.         pop     ds
  166.  
  167.         if    pwm
  168.         mov     al,0b6h
  169.         out     tccont,al               ;change timer to square wave gen mode
  170.  
  171.         in      al,speaker
  172.         and    al,0fch
  173.         out     speaker,al              ;speaker one shot disable
  174.         endif
  175.  
  176.         sti
  177.         ret
  178. restore endp
  179.  
  180. ;***********************************************************************
  181. ;
  182. ;  Initialise - save int vector contents, replace with my version
  183. ;
  184. ;***********************************************************************
  185.  
  186. initial proc near
  187.         cli
  188.         mov     cs:[dstemp],ds
  189.         mov     ax,3509h                        ;get old kbd int
  190.         int     21h
  191.         mov     word ptr cs:[kbdold],bx            ;save it
  192.         mov     word ptr cs:[kbdold+2],es
  193.         mov     dx,offset kbdint
  194.         push    ds
  195.         mov     ax,cs
  196.         mov     ds,ax
  197.         mov     ax,2509h
  198.         int     21h                             ;replace with mine
  199.         pop     ds
  200.         mov     byte ptr [kbdflag],0            ;no key activity
  201.  
  202.         if    pwm
  203.         mov     al,0b6h
  204.         out     tccont,al               ;change timer to square wave gen mode
  205.         mov     al,byte ptr[tconstant]
  206.     shr    al,1
  207.         out     tccount,al              ;produce mean equivalent dc voltage
  208.     xor    al,al
  209.         out     tccount,al
  210.         in      al,speaker
  211.         or      al,3
  212.         out     speaker,al              ;speaker one shot enable
  213.     else
  214.         mov     dx,[daout]
  215.         mov    al,127
  216.     out    dx,al
  217.         endif
  218.  
  219.         sti
  220.         ret
  221. initial endp
  222.  
  223.  
  224. ;******************************************************************************
  225. ;
  226. ;  Sample data from A/D port
  227. ;
  228. ;******************************************************************************
  229.  
  230. sample  proc near
  231.         cli
  232.  
  233.         in      al,21h
  234.         or      al,98h                      ;disable comms, printer interrupts
  235.         out     21h,al
  236.  
  237.         mov     ax,3508h
  238.         int     21h                             ;get system timer vector
  239.         mov     word ptr [sysold],bx
  240.         mov     word ptr [sysold+2],es          ;and save it
  241.  
  242.         mov     dx,offset sysint
  243.         push    ds
  244.         mov     ax,cs
  245.         mov     ds,ax
  246.         mov     ax,2508h
  247.         int     21h                             ;replace with new one
  248.         pop     ds
  249.  
  250.         mov     ah,byte ptr [trigger]
  251.         mov     dx,[daout]
  252. trig:   in      al,dx                           ;wait for trigger level
  253.         mov     cx,tdelay
  254. tdel:   loop    tdel                            ;delay before next sample taken
  255.         cmp     al,ah
  256.         jc      trig
  257.  
  258.         mov     al,36h
  259.         out     43h,al
  260.         mov     al,byte ptr [tconstant]
  261.         out     40h,al                          ;set to ~20kHz system timer!
  262.         mov     al,0
  263.         out     40h,al
  264.         sti
  265.  
  266.         mov     bx,[bufstart]
  267.         mov     di,[bufend]
  268.  
  269.         mov     es,[buffer+2]
  270.  
  271. sync:   hlt                                     ;wait for system interrupt
  272.         in      al,dx
  273.         mov     es:[bx],al                         ;store sample
  274.         inc     bx
  275.         cmp     bx,di
  276.         jbe     sync                            ;until buffer full
  277.  
  278.         call    vrestore
  279.  
  280.         cli
  281.         in      al,21h
  282.         and     al,67h
  283.         out     21h,al
  284.         sti
  285.  
  286.         ret
  287. sample  endp
  288.  
  289.  
  290. ;******************************************************************************
  291. ;
  292. ;  Scale waveform for PWM replay
  293. ;
  294. ;******************************************************************************
  295.  
  296. scalewave proc near
  297.  
  298.         push    ds
  299.  
  300.         mov     es,[bufferw+2]       ;copy from buffer to bufferw with scale
  301.         mov     si,[bufferw]
  302.         mov     cx,bufflen
  303.         inc     cx
  304.         mov     di,[buffer]
  305.         mov     ds,[buffer+2]
  306.  
  307. sloop:  mov     al,[di]              ;div 4 +1
  308.         shr     al,1
  309.         shr     al,1
  310.         inc     al
  311.         mov     es:[si],al
  312.         inc     si
  313.         inc     di
  314.         loop    sloop
  315.  
  316.         pop     ds
  317.         ret
  318. scalewave endp
  319.  
  320.  
  321. ;*************************************************************************
  322. ;
  323. ;  Echo - echos A/D to D/A for monitoring
  324. ;
  325. ;*************************************************************************
  326.  
  327. echo    proc near
  328.         cli
  329.  
  330.         push    bp
  331.         in      al,21h
  332.         or      al,98h                      ;disable comms, printer interrupts
  333.         out     21h,al
  334.  
  335.         mov     [sptemp],sp                     ;remember sp incase kbd abort
  336.         mov     al,1
  337.         mov     byte ptr [quickexit],al
  338.         mov     ax,3508h
  339.         int     21h                             ;get system timer vector
  340.         mov     word ptr [sysold],bx
  341.         mov     word ptr [sysold+2],es          ;and save it
  342.  
  343.         mov     dx,offset sysint
  344.         push    ds
  345.         mov     ax,cs
  346.         mov     ds,ax
  347.         mov     ax,2508h
  348.         int     21h                             ;replace with new one
  349.         pop     ds
  350.  
  351.         if      pwm
  352.         mov     al,0b0h
  353.         out     tccont,al                       ;change timer to one shot mode
  354.         mov     al,255
  355.         out     tccount,al
  356.         mov     al,0
  357.         out     tccount,al
  358.         mov     al,90h
  359.         out     tccont,al
  360.         endif
  361.  
  362.         mov     al,36h
  363.         out     43h,al
  364.         mov     al,byte ptr [tconstant]
  365.         out     40h,al                          ;set to ~20kHz system timer!
  366.         mov     al,0
  367.         out     40h,al
  368.         sti
  369.  
  370.         if      pwm
  371.         in      al,speaker
  372.         or      al,3
  373.         out     speaker,al                      ;speaker one shot enable
  374.         else
  375.         mov     dx,[daout]
  376.         endif
  377.  
  378.  
  379. eloop:
  380.         if      pwm
  381.         mov     dx,[daout]
  382.         endif
  383.  
  384.         in      al,dx
  385.  
  386.         if      pwm
  387.         shr     al,1
  388.         shr     al,1
  389.         inc     al
  390.         mov     dx,tccount
  391.         out     dx,al                   ;activate one shot
  392.         out     dx,al                   ;seems to need this else distortion
  393.         else
  394.         out     dx,al
  395.         endif
  396.  
  397.         hlt                             ;wait for system interrupt
  398.  
  399.         jmp     eloop                   ;exit via exitr
  400.  
  401. echo    endp
  402.  
  403.  
  404. ;*************************************************************************
  405. ;
  406. ;  Replay  - plays stored sound under interrupt control using fractional
  407. ;            addition, handles loop function, looks for keypresses
  408. ;
  409. ;*************************************************************************
  410.  
  411. replay  proc near
  412.         cli
  413.  
  414.         in      al,21h
  415.         or      al,98h                      ;disable comms, printer interrupts
  416.         out     21h,al
  417.  
  418.         push    bp
  419.         mov     [sptemp],sp                     ;remember sp incase kbd abort
  420.         mov     al,1
  421.         mov     byte ptr [quickexit],al
  422.         mov     ax,3508h
  423.         int     21h                             ;get system timer vector
  424.         mov     word ptr [sysold],bx
  425.         mov     word ptr [sysold+2],es          ;and save it
  426.  
  427.         mov     dx,offset sysint
  428.         push    ds
  429.         mov     ax,cs
  430.         mov     ds,ax
  431.         mov     ax,2508h
  432.         int     21h                             ;replace with new one
  433.         pop     ds
  434.  
  435.         if      pwm
  436.         mov     al,0b0h
  437.         out     tccont,al                       ;change timer to one shot mode
  438.         mov     al,255
  439.         out     tccount,al
  440.         mov     al,0
  441.         out     tccount,al
  442.         mov     al,90h
  443.         out     tccont,al
  444.         endif
  445.  
  446.         mov     al,36h
  447.         out     43h,al
  448.         mov     al,byte ptr [tconstant]
  449.         out     40h,al                          ;set to ~20kHz system timer!
  450.         mov     al,0
  451.         out     40h,al
  452.         sti
  453.  
  454.         if      pwm
  455.         in      al,speaker
  456.         or      al,3
  457.         out     speaker,al                      ;speaker one shot enable
  458.         endif
  459.  
  460. loopa:  mov     bx,[tinterval]
  461.         mov     si,bx                           ;local note duration counter
  462.         mov     bl,byte ptr [modulus]
  463.         mov     [modul],bl                      ;local modulus counter
  464.  
  465.         if      pwm
  466.         mov     es,[bufferw+2]
  467.         else
  468.         mov     es,[buffer+2]
  469.         endif
  470.  
  471.         mov     bx,[bufstart]
  472.         mov     bp,[increment]
  473.         mov     ah,byte ptr [loop]
  474.  
  475.         ife     pwm
  476.         mov     dx,[daout]
  477.         else
  478.         mov     dx,tccount
  479.         endif
  480.  
  481. repeat: mov     di,[bufend]
  482.         mov     ch,bl
  483.         mov     cl,0
  484.  
  485. loops:  add     cx,bp                   ; fractional add (ch.cl is result)
  486.         mov     bl,ch                   ; lsnib of buffer pointer
  487.         adc     bh,0
  488. waiti:  mov     al,es:[bx]                 ; get sample
  489.  
  490.         hlt                             ;wait for system interrupt
  491.  
  492.         if      pwm
  493.         out     dx,al                   ;activate one shot
  494.         out     dx,al                   ;seems to need this else distortion
  495.         else
  496.         out     dx,al
  497.         endif
  498.  
  499. testlop: cmp     bx,di
  500.         jb       loops
  501.         test    ah,ah                   ;loop mode?
  502.         jz      exitr
  503.         mov     bx,[bufloop]
  504.         jmp     repeat                  ;yes, restart from loop position
  505.  
  506. exitr:  mov     al,0
  507.         mov     byte ptr [quickexit],al
  508.         call    vrestore
  509.  
  510.         cli
  511.         in      al,21h                  ;enable serial/parallel ints
  512.         and     al,67h
  513.         out     21h,al
  514.         sti
  515.  
  516.         pop     bp
  517.         ret
  518. replay  endp
  519.  
  520.  
  521. ;*************************************************************************
  522. ;
  523. ;  Replayt - plays stored sound under interrupt control using fractional
  524. ;            addition, handles loop function, looks for keypresses. this
  525. ;            version uses timer control
  526. ;
  527. ;*************************************************************************
  528.  
  529. replayt proc near
  530.         cli
  531.  
  532.         in      al,21h
  533.         or      al,98h                      ;disable comms, printer interrupts
  534.         out     21h,al
  535.  
  536.         push    bp
  537.         mov     [sptemp],sp                     ;remember sp incase kbd abort
  538.         mov     al,1
  539.         mov     byte ptr [quickexit],al
  540.         mov     ax,3508h
  541.         int     21h                             ;get system timer vector
  542.         mov     word ptr [sysold],bx
  543.         mov     word ptr [sysold+2],es          ;and save it
  544.  
  545.         mov     dx,offset sysint
  546.         push    ds
  547.         mov     ax,cs
  548.         mov     ds,ax
  549.         mov     ax,2508h
  550.         int     21h                             ;replace with new one
  551.         pop     ds
  552.  
  553.         if      pwm
  554.         mov     al,0b0h
  555.         out     tccont,al                       ;change timer to one shot mode
  556.         mov     al,255
  557.         out     tccount,al
  558.         mov     al,0
  559.         out     tccount,al
  560.         mov     al,90h
  561.         out     tccont,al
  562.         endif
  563.  
  564.         mov     al,36h
  565.         out     43h,al
  566.         mov     al,byte ptr [tconstant]
  567.         out     40h,al                          ;set to ~20kHz system timer!
  568.         mov     al,0
  569.         out     40h,al
  570.         sti
  571.  
  572.         if      pwm
  573.         in      al,speaker
  574.         or      al,3
  575.         out     speaker,al                      ;speaker one shot enable
  576.         endif
  577.  
  578. loopat: mov     si,[tinterval]                  ;local note duration counter
  579.         mov     bl,byte ptr [modulus]
  580.         mov     [modul],bl                      ;local modulus counter
  581.  
  582.         if      pwm
  583.         mov     es,[bufferw+2]
  584.         else
  585.         mov     es,[buffer+2]
  586.         endif
  587.  
  588.         mov     bx,[bufstart]
  589.         mov     bp,[increment]
  590.         mov     ah,[modul]
  591.  
  592.         ife     pwm
  593.         mov     dx,[daout]
  594.         else
  595.         mov     dx,tccount
  596.         endif
  597.  
  598. repeatt: mov     di,[bufend]
  599.         mov     ch,bl
  600.         mov     cl,0
  601.  
  602. loopst: add     cx,bp                   ; fractional add (ch.cl is result)
  603.         mov     bl,ch                   ; lsnib of buffer pointer
  604.         adc     bh,0
  605. waitit: mov     al,es:[bx]              ; get sample
  606.  
  607.         hlt                             ;wait for system interrupt
  608.  
  609.         if      pwm
  610.         out     dx,al                   ;activate one shot
  611.         out     dx,al                   ;seems to need this else distortion
  612.         else
  613.         out     dx,al
  614.         endif
  615.  
  616.         dec     ah                      ;time to dec tinterval?
  617.         jz      ntestlop
  618.         cmp     bx,di
  619.         jb      loopst
  620.         test    byte ptr [loop],0ffh    ;loop mode?
  621.         jz      waith
  622.         mov     bx,[bufloop]
  623.         jmp     repeatt                 ;yes, restart from loop position
  624.  
  625. ntestlop: dec     si                    ;see if time up
  626.         mov     al,byte ptr [modulus]   ;reset modulus counter
  627.         mov     ah,al
  628.         js      timeupt                 ; yep, go and check if song mode
  629.         cmp     bx,di                   ;2nd copy of testlop avoids jump
  630.         jb      loopst
  631.         test    byte ptr [loop],0ffh    ;loop mode?
  632.         jz      waith
  633.         mov     bx,[bufloop]
  634.         jmp     repeatt                 ;yes, restart from loop position
  635.  
  636. timeupt: test    byte ptr [song],0ffh    ;song mode?
  637.         jnz     exitrt                  ;yes, immediate exit
  638.         jmp     loopat                  ;no, loop back to start of sound
  639.  
  640. waith:  test    si,0ffffh               ;wait for full duration
  641.         jns     waitit                  ;wait for keyboard or timer
  642. exitrt: jmp     exitr
  643.  
  644. replayt endp
  645.  
  646.  
  647. ;
  648. ; local procedures
  649. ;
  650.  
  651.  
  652. ;
  653. ; Speaker interrupt service routine
  654. ;
  655. ;  Does nothing except synchronise output operations
  656. ;
  657.  
  658. sysint  proc far
  659.         push    ax
  660.         mov     al,20h
  661.         out     20h,al                          ;EOI to int controller
  662.         pop     ax
  663.  
  664.         iret
  665.         sysint  endp
  666.  
  667. ;
  668. ; Comm1,2 interrupt service routine
  669. ;
  670. ;  Prevents mouse activity from slowing cpu during sampling/replay
  671. ;
  672.  
  673. comint  proc far
  674.         push    ax
  675.         mov     al,20h
  676.         out     20h,al                          ;EOI to int controller
  677.         pop     ax
  678.  
  679.         iret
  680.         comint  endp
  681.  
  682. ;
  683. ; Custom keyboard interrupt handler - handles keypresses, key releases (if
  684. ;             desired), modifies kbd flags. Note if TP4 kbd or screen
  685. ;             procedure was in progress, DS may have been changed, so restore
  686. ;             from dstemp.
  687. ;
  688.  
  689. kbdint  proc  far                               ;custom keyboard interrupt handler
  690.         push    ds
  691.         mov     ds,cs:[dstemp]
  692.         test    byte ptr [kbdmode],0ffh         ;handle key here?
  693.         jnz     kserv
  694.         pop     ds
  695.         jmp     cs:kbdold                       ;no, give to bios
  696. kserv:  push    ax
  697.         in      al,60h                          ;get key code
  698.         cmp     al,lshiftr                      ;always note shift releases
  699.         jz      notrel
  700.         cmp     al,rshiftr
  701.         jz      notrel
  702.         test    byte ptr [release],0ffh         ;release sensitive?
  703.         jnz     isrel
  704.         test    al,al                           ;no, ignore if key released
  705.         js      pressd
  706.         jmp     notrel
  707. isrel:                                          ;release sensitive
  708.         cmp     al,byte ptr [keyval]            ;ignore if same key as last time
  709.         jz      pressd                          ; ie ignore autorepeat
  710.         test    al,al
  711.         jns     notrel                          ;if keydown, go record it
  712.         mov     ah,al
  713.         xor     ah,byte ptr [keyval]
  714.         cmp     ah,129                          ;record release of last key but
  715.         jns     pressd                          ; not release of older key
  716. notrel: mov     byte ptr [keyval],al            ;record keypressed
  717.         mov     byte ptr [kbdflag],al
  718. pressd: mov     al,0ffh
  719.         in      al,61h
  720.         or      al,80h
  721.         out     61h,al
  722.         and     al,7fh
  723.         out     61h,al
  724.         mov     al,20h                          ;EOI
  725.         out     20h,al
  726.         pop     ax
  727.         test    byte ptr [quickexit],0ffh
  728.         jz      noquick
  729.         test    byte ptr [kbdflag],0ffh
  730.         jz      noquick
  731.         mov     es,[sptemp]
  732.         pop     ds
  733.         push    es
  734.         pop     sp
  735.         jmp     exitr
  736.  
  737. noquick: pop     ds
  738.         iret
  739.         kbdint  endp
  740.  
  741.  
  742. vrestore proc  near                      ;restore hardware, system timer vector
  743.         cli
  744.         mov     al,36h
  745.         out     43h,al
  746.         xor     al,al
  747.         out     40h,al                          ;restore system timer frequency
  748.         out     40h,al
  749.  
  750.         mov     al,0b6h
  751.         out     tccont,al               ;change timer to square wave gen mode
  752.         mov     al,byte ptr[tconstant]
  753.     shr    al,1
  754.         out     tccount,al              ;produce mean equivalent dc voltage
  755.     xor    al,al
  756.         out     tccount,al
  757.  
  758.         push    ds
  759.         lds     dx,sysold
  760.         mov     ax,2508h                        ;restore old system timer vec
  761.         int     21h
  762.         pop     ds
  763.         sti
  764.         ret
  765.         vrestore endp
  766.  
  767. code    ends
  768.         end
  769.